/** \file matriz.hpp
 *  \brief Definição da classe matriz e de algumas funções e operadores relacionados às algebra linear matricial
 *  \author Geraldo Francisco de S. Rebouças | gfs.reboucas@gmail.com
 *  \since 28/11/2012
 *  \version 1.0
 *  \date 02/12/2012
 *  \see Veja [Matrix Computations] e [Applied Linear Algebra] para entender a teoria relacionada à implementação desta classe. */

// Diretrizes de pré-processamento para compilação condicional. Se matriz.hpp não foi definido, defina matriz.hpp. Isso evita a inserção duplicada de uma biblioteca num mesmo código-fonte.
#ifndef _MATRIZ_HPP
#define _MATRIZ_HPP

#include <iostream>
#include <valarray>
#include "vetor.hpp"

using namespace std;

class vetor;

/** \class matriz
 *  \brief Classe para operações matriciais diversas */
class matriz
{
    private:
        int l; ///< Quantidade de linhas da matriz
        int c; ///< Quantidade de colunas da matriz
//        /// matriz A bad_alloc fdp!
//        valarray <vetor> A;
        valarray <valarray <double> > A; ///< Estrutura de dados que armazena os elementos da matriz
//        valarray < valarray <complex <double> > > Ac; ///< estrutura de dados que irá armazenar os elementos de uma matriz complexa
    public:
        matriz(); ///< Construtor default
        ~matriz(); ///< Destrutor
        matriz(int, int); ///< Construtor 01, define apenas a quantidade de linhas e colunas
        matriz(valarray <vetor>, int, int); ///< Construtor 02, faz o mesmo que o 01, inicializando A com base num valarray de vetor
        matriz(valarray < valarray <double> >, int, int); ///< Construtor 03, faz o mesmo que o 01, inicializando A com base num valarray bi-dimensional
        matriz(const matriz &); ///< Construtor de cópia
        void setNull(int, int); ///< Transforma a matriz numa matriz nula\f$ 0_{i j} \f$
        void setIdent(int); ///< Transforma a matriz numa matriz identidade de ordem \f$ k \f$, \f$ I_k \f$
        void setLine(vetor, int);
        void setCol(vetor, int);
        void show(); ///< Exibe os elementos da matriz
        vetor lin(int); ///< Retorna a i-ésima linha da matriz: \f$ A_{i,-} \f$
        vetor col(int); ///< Retorna a i-ésima coluna da matriz: \f$ A_{-,i} \f$
        int retl(); ///< Retorna a quantidade de linhas da matriz
        int retc(); ///< Retorna a quantidade de colunas da matriz
        matriz minimat(int, int); ///< Retorna uma matriz igual a original excluindo a linha e a coluna relacionadas ao elemento \f$ A_{a,b} \f$ (fazer)
        matriz minimat(int, int, int, int); ///< Retorna uma matriz igual a original indo da linha \f$ a \f$ até a \f$ b \f$ e da coluna \f$ c \f$ até a \f$ d \f$ : \f$ A_{a:b,c:d} \f$ (fazer)
        matriz& operator+=(const matriz &); ///< Retorna a soma entre duas matrizes, armazenando o resultado na primeira delas
        matriz& operator=(const matriz &); ///< Operador de atribuição, torna uma matriz igual a outra  \f$ A = B \f$
        matriz operator-(); ///< Retorna o inverso aditivo da matriz: \f$ -A \f$
        double& operator()(int, int); ///< Retorna o elemento  \f$ A_{i j} \f$ da matriz
};

matriz operator*(double, matriz); ///< Retorna o produto entre uma constante e uma matriz: \f$ k M \f$
matriz operator*(matriz, double); ///< Retorna o produto entre uma matriz e uma constante: \f$ M k \f$
matriz operator*(matriz, matriz); ///< Retorna o produto entre duas matrizes:  \f$ A B \f$
matriz operator+(matriz, matriz); ///< Retorna a soma entre duas matrizes:  \f$ A + B \f$
matriz operator-(matriz, matriz); ///< Retorna a subtração entre duas matrizes:  \f$ A - B \f$
matriz operator^(matriz, int); ///< Retorna a k-ésima potência de uma matriz:  \f$ A^k \f$ (fazer)
ostream& operator<<(ostream&, matriz); ///< Imprime os elementos da matriz numa linha, utilizado apenas p/ saídas em arquivo
matriz transp(matriz); ///< Retorna a transposta da matriz:  \f$ A^T \f$ (fazer)
double traco(matriz); ///< Retorna o traço da matriz (fazer)

#endif // _MATRIZ_HPP
